/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is ThumbsDown.
 *
 * The Initial Developer of the Original Code is
 * Atte Kemppilä.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK ***** */


var gThumbsDown =
{
    onLoad: function()
    {
        Cu.import("resource://thumbsdown/ThumbsDown.jsm");
        
        var self = this;
        AddonManager.getAddonByID(ThumbsDown.EXT_ID, function(addon) { self.onLoadWithAddon(addon); });
    },
    
    onLoadWithAddon: function(addon)
    {
        // load os specific default preferences
        Cu.import("resource://thumbsdown/default-preferences.jsm", this);
        var prefsPath = "platform/" + Services.appinfo.OS + "/defaults/preferences/thumbsdown.js";
        this.loadDefaultPrefs(addon, prefsPath);
        
        this.util = {};
        Cu.import("resource://thumbsdown/util.jsm", this.util);
        
        // elements
        this.$active = document.getElementById("thumbsdown_active");
        
        // localization
        this.util._ = this.util.getStringBundleGetter(document.getElementById("thumbsdown_stringBundle"));
        
        // init shortcut keys
        this.util.initKey(document.getElementById("thumbsdown_key_toggleStatus"),         "extensions.thumbsdown.keys.toggleStatus");
        this.util.initKey(document.getElementById("thumbsdown_key_activateAndSelectAll"), "extensions.thumbsdown.keys.activateAndSelectAll");
        this.util.initKey(document.getElementById("thumbsdown_key_download"),             "extensions.thumbsdown.keys.download");
        
        // stylesheet
        var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
        var uri = Services.io.newURI("chrome://thumbsdown/content/thumbsdown.css", null, null);
        if (! sss.sheetRegistered(uri, sss.USER_SHEET))
            sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
        
        // listeners
        gBrowser.tabContainer.addEventListener("TabSelect", function(e) { gThumbsDown.onTabSelect(e) }, false);
        gBrowser.tabContainer.addEventListener("TabClose", function(e) { gThumbsDown.onTabClose(e) }, false);
        gBrowser.addEventListener("DOMContentLoaded", function(e) { gThumbsDown.onPageLoad(e); }, false);
        gBrowser.addEventListener("click", function(e) { gThumbsDown.onContentClick(e); }, true);
        gBrowser.addEventListener("mouseup", function(e) { gThumbsDown.onContentMouseUp(e); }, true);
        
        // popup menu listeners
        document.getElementById("menu_ToolsPopup").addEventListener("popupshowing", function(e) { gThumbsDown.onToolsMenuShowing(e); }, false);
        document.getElementById("contentAreaContextMenu").addEventListener("popupshowing", function(e) { gThumbsDown.onContextMenuShowing(e); }, false);
        // don't open tooltip if context menu is already open
        document.getElementById("thumbsdown_buttonTooltip").addEventListener("popupshowing", function(e) { if (document.popupNode) e.preventDefault(); } ,false);
        
        // init ui
        this._initToolbar();
        var ctx = this._getContext(null, true, false);
        this._updateUi(ctx, true);
    },
    
    _initToolbar: function()
    {
        let buttonId = "thumbsdown_button";
        let buttonPref = "initialized.button";
        
        if (! ThumbsDown.prefs.prefHasUserValue(buttonPref))
        {
            if (! document.getElementById(buttonId))
            {
                let $toolbar = document.getElementById("addon-bar");
                $toolbar.insertItem(buttonId);
                $toolbar.setAttribute("currentset", $toolbar.currentSet);
                document.persist($toolbar.id, "currentset");
                $toolbar.collapsed = false;
            }
            
            ThumbsDown.prefs.setBoolPref(buttonPref, true);
        }
    },
    
    onToolsMenuShowing: function(e)
    {
        var show = ThumbsDown.prefs.getBoolPref("showInToolsMenu");
        document.getElementById("thumbsdown_toolsMenu_menu").hidden = (! show);
    },
    
    onContextMenuShowing: function(e)
    {
        var ctx = this._getContext(null, false, false);
        if (ctx && ctx.isActive)
        {
            var hijack = ThumbsDown.prefs.getBoolPref("hijackContextMenu");
            if (hijack)
            {
                e.stopPropagation();
                e.preventDefault();
                var contextMenu = document.getElementById("thumbsdown_hijackedContextMenu");
                // if popup x,y is the same as click point, popup is closed immediately on mouse button release -> shift popup a bit (+2)
                contextMenu.openPopup(null, "", e.clientX + 2, e.clientY + 2, true, false);
                return;
            }
        }
        var show = ThumbsDown.prefs.getBoolPref("showInContextMenu");
        document.getElementById("thumbsdown_contextMenu_menu").hidden = (! show);
    },
    
    onTabSelect: function(e)
    {
        var ctx = this._getContext(null, true, false);
        this._updateUi(ctx, true);
    },
    
    onTabClose: function(e)
    {
        var browser = e.target.linkedBrowser;
        var ctx = this._getContext(browser, false, false);
        if (! ctx)
            return;
        ctx.isActive = false;
    },
    
    onPageLoad: function(e)
    {
        var doc = e.originalTarget;
        if (! (doc instanceof HTMLDocument))
            return;
        if (doc.defaultView.frameElement)
            return;
        var browser = gBrowser.getBrowserForDocument(doc);
        var ctx = this._getContext(browser, false, false);
        if (! ctx)
            return;
        ctx.isActive = false;
        if (browser != gBrowser.selectedBrowser)
            return;
        this._updateUi(ctx);
    },
    
    onContentClick: function(e)
    {
        if (! (e.button == 0))
            return;
        var ctx = this._getContext(null, false, false);
        if (! (ctx && ctx.isActive))
            return;
        var elem = e.originalTarget;
        var thumbnails = ThumbsDown.getThumbnails(elem);
        if (thumbnails.length == 0)
            return;
        var changed = ctx.toggleThumbnails(thumbnails);
        e.stopPropagation();
        e.preventDefault();
        if (! changed)
            return;
        this._updateUi(ctx);
    },
    
    onContentMouseUp: function(e)
    {
        var ctx = this._getContext(null, false, false);
        if (! (ctx && ctx.isActive))
            return;
        var changed = this._selectFromSelection(ctx);
        if (! changed)
            return;
        this._updateUi(ctx);
    },
    
    _selectFromSelection: function(ctx)
    {
        var selection = document.commandDispatcher.focusedWindow.getSelection();
        if (selection.isCollapsed)
            return false;
        var range = selection.getRangeAt(0);
        var thumbnails = ThumbsDown.getThumbnails(range);
        var changed = ctx.selectThumbnails(thumbnails);
        selection.removeAllRanges();
        return changed;
    },
    
    onButtonClick: function(e)
    {
        // single click
        if      ((e.button == 0) && (e.detail == 1))
            this.toggleStatus();
        // double click
        else if ((e.button == 0) && (e.detail == 2))
        {
            this.activate(null, false);
            this.selectAll();
        }
        // single middle click
        else if ((e.button == 1) && (e.detail == 1))
            this.download();
    },
    
    toggleStatus: function(browser)
    {
        if (! browser)
            browser = gBrowser.selectedBrowser;
        var ctx = this._getContext(browser, false, false);
        if (ctx && ctx.isActive)
            this.deactivate(browser);
        else
            this.activate(browser, true);
    },
    
    activate: function(browser, selectFromSelection)
    {
        if (! browser)
            browser = gBrowser.selectedBrowser;
        var doc = browser.contentDocument;
        // TODO: better valid doc check (image is HTMLDocument)
        if (! (doc instanceof HTMLDocument))
            return;
        var ctx = this._getContext(browser, true, true);
        if (ctx.isActive)
            return;
        if (! this._checkSettings())
            return;
        ctx.isActive = true;
        if (selectFromSelection)
            this._selectFromSelection(ctx);
        else
            document.commandDispatcher.focusedWindow.getSelection().removeAllRanges();
        this._updateUi(ctx);
    },
    
    deactivate: function(browser)
    {
        var ctx = this._getContext(browser, false, false);
        if (! ctx)
            return;
        ctx.isActive = false;
        this._updateUi(ctx);
    },
    
    selectAll: function(browser)
    {
        if (! browser)
            browser = gBrowser.selectedBrowser;
        var ctx = this._getContext(browser, false, false);
        if (! (ctx && ctx.isActive))
            return;
        var doc = browser.contentDocument;
        var thumbnails = ThumbsDown.getThumbnails(doc);
        var changed = ctx.selectThumbnails(thumbnails);
        if (changed)
            this._updateUi(ctx);
    },
    
    download: function(browser)
    {
        if (! browser)
            browser = gBrowser.selectedBrowser;
        var ctx = this._getContext(browser, false, false);
        if (! (ctx && ctx.isActive))
            return;
        ctx.download(browser);
        this._updateUi(ctx);
    },
    
    startRange: function()
    {
        let ctx = this._getContext(null, false, false);
        if (! (ctx && ctx.isActive))
            return;
        let elem = gContextMenu.target;
        ctx.startRange(elem);
        this._updateUi(ctx);
    },
    
    endRange: function()
    {
        let ctx = this._getContext(null, false, false);
        if (! (ctx && ctx.isActive))
            return;
        let elem = gContextMenu.target;
        let range = ctx.endRange(elem);
        let thumbnails = ThumbsDown.getThumbnails(range);
        let changed = ctx.selectThumbnails(thumbnails);
        this._updateUi(ctx);
    },
    
    /**
     * Retrieves ThumbsDown Context object for browser.
     *
     * @param browser 
     * browser from where the context is looked up. 
     * If null, defaults to current tab.
     * @param create if true and context doesn't exist, creates a new
     * @param persist if true, persists created context
     *
     * @return context object or null, if it doesn't exist and a new was not created
     */
    _getContext: function(browser, create, persist)
    {
        if (! browser)
            browser = gBrowser.selectedBrowser;
        var ctx = browser.thumbsdown;
        if (ctx)
            return ctx;
        if (! create)
            return null;
        ctx = ThumbsDown.newContext();
        if (persist)
            browser.thumbsdown = ctx;
        return ctx;
    },
    
    _checkSettings: function()
    {
        var title = this.util._("error.title");
        
        var dirPath = ThumbsDown.prefs.getComplexValue("downloadDir", Ci.nsISupportsString).data;
        
        try
        {
            var dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
            dir.initWithPath(dirPath);
        }
        catch (e)
        {
            dir = null;
        }
        
        // is download directory set and valid file path?
        if ((dirPath.trim().length == 0) || (! dir))
        {
            var msg = this.util._("error.noDir");
            var button0Label = this.util._("openPreferences");
            var flags =
                Ci.nsIPromptService.BUTTON_POS_0 * Ci.nsIPromptService.BUTTON_TITLE_IS_STRING +
                Ci.nsIPromptService.BUTTON_POS_1 * Ci.nsIPromptService.BUTTON_TITLE_CANCEL;
            
            var result = Services.prompt.confirmEx(window, title, msg, flags, button0Label, null, null, null, {});
            
            if (result == 0)
                ThumbsDown.openPrefWindow("main");
            
            return false;
        }
        
        // does download directory exist?
        var warnMissingFolder = ThumbsDown.prefs.getBoolPref("warnMissingDownloadFolder");
        if (warnMissingFolder && (! (dir.exists() && dir.isDirectory())))
        {
            var msg = this.util._("error.dirDoesNotExist", dirPath);
            var button0Label = this.util._("openPreferences");
            var checkLabel = this.util._("warn.check");
            var check = {value: false};
            var flags =
                Ci.nsIPromptService.BUTTON_POS_0 * Ci.nsIPromptService.BUTTON_TITLE_IS_STRING +
                Ci.nsIPromptService.BUTTON_POS_1 * Ci.nsIPromptService.BUTTON_TITLE_CANCEL;
            
            var result = Services.prompt.confirmEx(window, title, msg, flags, button0Label, null, null, checkLabel, check);
            
            if (check.value)
                ThumbsDown.prefs.setBoolPref("warnMissingDownloadFolder", false);
            
            if (result == 0)
                ThumbsDown.openPrefWindow("main");
            
            return false;
        }
        
        // any scripts?
        if (ThumbsDown.ScriptStore.getScripts(true) == 0)
        {
            var msg = this.util._("error.noScripts");
            var button0Label = this.util._("openHomePage");
            var flags =
                Ci.nsIPromptService.BUTTON_POS_0 * Ci.nsIPromptService.BUTTON_TITLE_IS_STRING +
                Ci.nsIPromptService.BUTTON_POS_1 * Ci.nsIPromptService.BUTTON_TITLE_CANCEL;
            
            var result = Services.prompt.confirmEx(window, title, msg, flags, button0Label, null, null, null, {});
            
            if (result == 0)
                ThumbsDown.openHomePage();
            
            return false;
        }
        
        return true;
    },
    
    _updateUi: function(ctx, force)
    {
        var $ = function(id) { return document.getElementById(id); }
        
        // is update neccessary
        var currentContext = this._getContext(null, false, false);
        var isUiActive = (this.$active.getAttribute("active") == "true");
        if (! (force || ((ctx.isActive || isUiActive) && (ctx == currentContext))))
            return;
        
        this.$active.setAttribute("active", ctx.isActive);
        
        // toolbar
        var $buttonLabel = document.getElementById("thumbsdown_buttonLabel");
        if ($buttonLabel)
            $buttonLabel.setAttribute("value", ctx.thumbCtxs.length);
        
        // commands
        $("thumbsdown_cmd_activate").setAttribute("disabled", ctx.isActive);
        $("thumbsdown_cmd_deactivate").setAttribute("disabled", (! ctx.isActive));
        $("thumbsdown_cmd_selectAll").setAttribute("disabled", (! ctx.isActive));
        $("thumbsdown_cmd_download").setAttribute("disabled", (! ctx.isActive));
        $("thumbsdown_cmd_startRange").setAttribute("disabled", (! (ctx.isActive && (! ctx.range))));
        $("thumbsdown_cmd_endRange").setAttribute("disabled", (! (ctx.isActive && ctx.range)));
        
        // misc
        for each (let elem in this.util.NodeIterator(document.getElementsByClassName("thumbsdown_range_separator")))
            elem.hidden = (! ctx.isActive);
    },
}


window.addEventListener("load", function() { gThumbsDown.onLoad(); }, false);
